<?php
/**
 * Created by PhpStorm.
 * User: zhangxiaomin
 * Date: 2016/12/21
 * Time: 上午9:48
 */

namespace App\Services\Kdniao;


use App\Http\Controllers\Api\V1\App\Common\LogisticTraceController;
use App\Models\Setting;
use App\Models\Store;
use App\Services\Utils\ApiChecker;

/**
 * @link https://www.kdniao.com/
 */
class Kdniao
{
    use ApiChecker;

    const REQUEST_DATA_TYPE_JSON = '2';

    /**
     * 直接查询物流
     */
    const REQUEST_TYPE_TRACES = '1002';
    /**
     * 订阅物流推送
     */
    const REQUEST_TYPE_SUBSCRIBE = '1008';
    /**
     * @var string
     */
    const LOGISTIC_STATE_RECEIVED = '3';
    /**
     * @var mixed 商户id
     */
    protected $e_business_id;

    /**
     * @var string $app_key
     */
    protected $app_key;

    /**
     * @var string
     */
    protected $api_url;

    const API_URL = "http://api.kdniao.com/api/dist";

    const API_SANDBOX_URL = "http://sandboxapi.kdniao.com:8080/kdniaosandbox/gateway/exterfaceInvoke.json";

    /**
     * Kdniao constructor.
     * @throws \App\Exceptions\ApiAbstractException
     */
    public function __construct()
    {
        $config = $this->checkGetConfig();

        $this->e_business_id = $config['logistic_kdniao_e_business_id'];

        $this->app_key = $config['logistic_kdniao_app_key'];

        $this->api_url = self::API_URL;
    }

    public function useSandBox(): self
    {
        $this->api_url = self::API_SANDBOX_URL;

        return $this;
    }
    /**
     * @param string $shipper_code - 快递公司编码
     * @param string $logistic_code - 快递单号
     *
     * @see ShipperCodeMap::get() - 快递公司编码表
     *
     * @return array
     * @throws \Exception
     */
    public function queryTraces(string $shipper_code, string $logistic_code): array
    {
        $request_json = json_encode([
            'ShipperCode'  => $shipper_code,
            'LogisticCode' => $logistic_code,
        ]);

        /**
         * @link https://www.kdniao.com/api-track - 参数文档
         */
        $data = [
            'EBusinessID' => $this->e_business_id,
            'RequestType' => self::REQUEST_TYPE_TRACES,
            'DataType'    => self::REQUEST_DATA_TYPE_JSON,
            'RequestData' => urlencode($request_json),
            'DataSign'    => $this->encrypt($request_json),
        ];

        $result = $this->curlPost($data);

        /**
         * @see MockData::responseInvalidShipperCode();
         * @see MockData::responseSucceedNoTrace();
         */
        return $this->parseCheckJson($result);
    }

    /**
     * @param string $shipper_code - 快递公司编码
     * @param string $logistic_code - 快递单号
     * @param string|null $order_id
     *
     * @return array
     * @throws \Exception
     * @see ShipperCodeMap::get() - 快递公司编码表
     */
    public function subscribeTraces(string $shipper_code, string $logistic_code, string $order_id): array
    {
        $request_json = json_encode([
            'ShipperCode'  => $shipper_code,
            'LogisticCode' => $logistic_code,
            'OrderCode'    => $order_id,
        ]);

        /**
         * @link https://www.kdniao.com/api-follow - 参数文档
         * @link https://www.kdniao.com/UserCenter/v2/SandBox/Index.aspx - 回调地址配置
         * @used-by LogisticTraceController::notify() - 回调处理
         */
        $data = [
            'EBusinessID' => $this->e_business_id,
            'RequestType' => self::REQUEST_TYPE_SUBSCRIBE,
            'DataType'    => self::REQUEST_DATA_TYPE_JSON,
            'RequestData' => urlencode($request_json),
            'DataSign'    => $this->encrypt($request_json),
        ];

        $result = $this->curlPost($data);

        /**
         * @see MockData::subscribeResponseOk()
         */
        return $this->parseCheckJson($result);
    }

    /**
     * 判断时候为json类型
     *
     * @param string $json
     *
     * @return array
     *
     * @throws \Exception
     */
    private function parseCheckJson($json)
    {
        $data = json_decode($json, true);

        if (json_last_error()) {
            throw new \Exception(json_last_error_msg() ?: 'unknown json parse error!');
        } else {
            return $data;
        }
    }

    /**
     * post提交既是查询的请求
     *
     * @param $data
     *
     * @return string,
     */
    private function curlPost($data)
    {
        $post_data = http_build_query($data);
        $url_info = parse_url($this->api_url);
        $url_info['port'] = $url_info['port'] ?? 80;
        $http_message = "POST " . $url_info['path'] . " HTTP/1.0\r\n";
        $http_message.= "Host:" . $url_info['host'] . "\r\n";
        $http_message.= "Content-Type:application/x-www-form-urlencoded\r\n";
        $http_message.= "Content-Length:" . strlen($post_data) . "\r\n";
        $http_message.= "Connection:close\r\n\r\n";
        $http_message.= $post_data;
        $fd = fsockopen($url_info['host'], $url_info['port']);
        fwrite($fd, $http_message);
        $gets = "";
        while (!feof($fd)) {
            if (($header = @fgets($fd)) && ($header == "\r\n" || $header == "\n")) {
                break;
            }
        }
        while (!feof($fd)) {
            $gets.= fread($fd, 128);
        }
        fclose($fd);

        return $gets;
    }

    /**
     * 电商sign签名
     * @param $data
     * @return string, DataSign签名
     */
    private function encrypt($data)
    {
        return urlencode(base64_encode(md5($data.$this->app_key)));
    }

    /**
     * @throws \App\Exceptions\ApiAbstractException
     */
    private function checkGetConfig(): array
    {
        $setting = Setting::findConfigByCode('logistic_kdniao', Store::STORE_ID_DEFAULT);

        $this->checkIsTrue(! empty($setting['logistic_kdniao_status']), 'logistic kdniao setting status off!');

        return $setting;
    }
}

class MockData
{
    static function responseInvalidShipperCode()
    {
        return [
            "LogisticCode" => "123123",
            "ShipperCode"  => "123",
            "Traces"       => [],
            "State"        => "0",
            "EBusinessID"  => "1272627",
            "Reason"       => "无效的输入[【ShipperCode】物流公司编号不正确]",
            "Success"      => false,
        ];
    }

    static function responseSucceedNoTrace()
    {
        return [
            "LogisticCode" => "589707398027",
            "ShipperCode"  => "SF",
            "Traces"       => [],
            "State"        => "0",
            "EBusinessID"  => "1272627",
            "Reason"       => "暂无轨迹信息",
            "Success"      => true,
        ];
    }

    static function responseSucceed()
    {
        return [
            "LogisticCode" => "589707398027",
            "ShipperCode"  => "SF",
            "Traces"       => [ // order by time asc
                [
                    "AcceptTime"    => "2015-03-07 15:26:09",
                    "AcceptStation" => "深圳市横岗速递营销部已收件，（揽投员姓名：周宏彪;联系电话：13689537568）",
                    "Remark"        => "",
                ],
                [
                    "AcceptTime"    => "2015-03-08 16:32:00",
                    "AcceptStation" => "离开深圳市 发往广州市",
                    "Remark"        => "",
                ],
            ],
            "State"        => "0",
            "EBusinessID"  => "1272627",
            "Reason"       => "暂无轨迹信息",
            "Success"      => true,
        ];
    }

    /**
     * 订单成功通知
     * @return array
     */
    public function subscribeResponseOk()
    {
        return [
            "UpdateTime"  => "2019-01-03 15:30:22",
            "EBusinessID" => "1417458",
            "Success"     => true,
        ];
    }

    /**
     * 订单回调通知示例
     *
     * @link https://www.kdniao.com/api-follow - 参数文档
     *
     * @return array
     */
    public function notifyData()
    {
        return [
            /**
             * @see \App\Services\Kdniao\MockData::notifyDataRequestJsonParsed
             */
            'RequestData' => '{"PushTime":"2019-01-03 15:56:11" ... json string',
            'DataSign'    => 'MGFjYmU5YWY3ODBjOGRjZjlkMWJkZTljY2M2MDZiNzU=',
            'RequestType' => '101',
        ];
    }

    public function notifyDataRequestJsonParsed()
    {
         return [
             "PushTime"    => "2019-01-03 15:56:11",
             "EBusinessID" => "1417458",
             "Data"        => [
                 [
                     "Success"      => true,
                     "State"        => "3",
                     "EBusinessID"  => "1417458",
                     "LogisticCode" => "803593772551276310",
                     "ShipperCode"  => "YTO",
                     "OrderCode"    => "123",
                     "Traces"       => [
                         [
                             "AcceptStation" => "【广东省深圳市华茂公司】 已收件",
                             "AcceptTime"    => "2018-12-22 22:31:26",
                         ],
                         [
                             "AcceptStation" => "【广东省深圳市华茂公司】 已打包",
                             "AcceptTime"    => "2018-12-22 22:54:17",
                         ],
                         [
                             "AcceptStation" => "【广东省广州市天河区东圃公司】 已收入",
                             "AcceptTime"    => "2018-12-23 14:14:21",
                         ],
                         [
                             "AcceptStation" => "客户 签收人: 前台 已签收 感谢使用圆通速递，期待再次为您服务",
                             "AcceptTime"    => "2018-12-24 10:58:39",
                         ],
                     ],
                 ],
             ],
             "Count"       => "1",
         ];
    }
}